﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace KTDSMS
{
    public class KtdSms
    {
        private static AutoResetEvent readNow = new AutoResetEvent(false);
        public AutoResetEvent receiveNow;

        public SerialPort OpenPort(string p_strPortName, int p_uBaudRate, int p_uDataBits, int p_uReadTimeout, int p_uWriteTimeout)
        {
            this.receiveNow = new AutoResetEvent(false);
            SerialPort serialPort = new SerialPort();
            try
            {
                serialPort.PortName = p_strPortName;
                serialPort.BaudRate = p_uBaudRate;
                serialPort.DataBits = p_uDataBits;
                serialPort.StopBits = StopBits.One;
                serialPort.Parity = Parity.None;
                serialPort.ReadTimeout = p_uReadTimeout;
                serialPort.WriteTimeout = p_uWriteTimeout;
                serialPort.Encoding = Encoding.GetEncoding("iso-8859-1");
                serialPort.DataReceived += new SerialDataReceivedEventHandler(this.port_DataReceived);
                serialPort.Open();
                serialPort.DtrEnable = true;
                serialPort.RtsEnable = true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return serialPort;
        }// end OpenPort

        public void ClosePort(SerialPort port)
        {
            try
            {
                port.Close();
                port.DataReceived -= new SerialDataReceivedEventHandler(this.port_DataReceived);
                port = (SerialPort)null;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }// end ClosePort

        public string ExecCommand(SerialPort port, string command, int responseTimeout, string errorMessage)
        {
            try
            {
                port.DiscardOutBuffer();
                port.DiscardInBuffer();
                this.receiveNow.Reset();
                port.Write(command + "\r");
                string str = this.ReadResponse(port, responseTimeout);
                if (str.Length == 0)
                    throw new ApplicationException("No success message was received.");
                else
                    return str;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }// ExecCommand

        public void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                if (e.EventType != SerialData.Chars)
                    return;
                this.receiveNow.Set();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }// port_DataReceived

        public string ReadResponse(SerialPort port, int timeout)
        {
            string str1 = string.Empty;
            try
            {
                do
                {
                    if (this.receiveNow.WaitOne(timeout, false))// Gui tin
                    {
                        string str2 = port.ReadExisting();
                        str1 = str1 + str2;
                    }
                    else
                        goto label_4;
                }
                while (!str1.EndsWith("\r\nOK\r\n") && !str1.EndsWith("\r\n> ") && !str1.EndsWith("\r\nERROR\r\n"));
                goto label_8;
            label_4:
                if (str1.Length > 0)
                    throw new ApplicationException("Response received is incomplete.");
                else
                    throw new ApplicationException("No data received from phone.");
            }
            catch (Exception ex)
            {
                throw ex;
            }
        label_8:
            return str1;
        }//end ReadResponse

        public int CountSMSmessages(SerialPort port)
        {
            int num = 0;
            try
            {
                string str1 = this.ExecCommand(port, "AT", 300, "No phone connected at ");
                str1 = this.ExecCommand(port, "AT+CMGF=1", 300, "Failed to set message format.");
                string command = "AT+CPMS?";
                string str2 = this.ExecCommand(port, command, 1000, "Failed to count SMS message");
                int length = str2.Length;
                if (str2.Length >= 45 && str2.StartsWith("AT+CPMS?"))
                {
                    string[] strArray = str2.Split(',');
                    string str3 = strArray[0];
                    num = Convert.ToInt32(strArray[1]);
                }
                else if (str2.Contains("ERROR"))
                    str1 = "Following error occured while counting the message" + str2.Trim();
                return num;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }// end CountSMSmessages

        public ShortMessageCollection ReadSMS(SerialPort port, string p_strCommand)
        {
            ShortMessageCollection messageCollection;
            try
            {
                this.ExecCommand(port, "AT", 300, "No phone connected");
                this.ExecCommand(port, "AT+CMGF=1", 300, "Failed to set message format.");
                this.ExecCommand(port, "AT+CSCS=\"PCCP437\"", 300, "Failed to set character set.");
                this.ExecCommand(port, "AT+CPMS=\"SM\"", 300, "Failed to select message storage.");
                messageCollection = this.ParseMessages(this.ExecCommand(port, p_strCommand, 5000, "Failed to read the messages."));
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return messageCollection ?? (ShortMessageCollection)null;
        }//end ReadSMS

        public ShortMessageCollection ParseMessages(string input)
        {
            ShortMessageCollection messageCollection = new ShortMessageCollection();
            try
            {
                for (Match match = new Regex("\\+CMGL: (\\d+),\"(.+)\",\"(.+)\",(.*),\"(.+)\"\\r\\n(.+)\\r\\n").Match(input); match.Success; match = match.NextMatch())
                    messageCollection.Add(new ShortMessage()
                    {
                        Index = match.Groups[1].Value,
                        Status = match.Groups[2].Value,
                        Sender = match.Groups[3].Value,
                        Alphabet = match.Groups[4].Value,
                        Sent = match.Groups[5].Value,
                        Message = match.Groups[6].Value
                    });
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return messageCollection;
        }// end ParseMessages

        public bool sendMsg(SerialPort port, string PhoneNo, string Message)
        {
            bool flag = false;
            try
            {
                string str1 = this.ExecCommand(port, "AT", 300, "No phone connected");

                str1 = this.ExecCommand(port, "AT+CMGF=1", 300, "Failed to set message format.");

                string command1 = "AT+CMGS=\"" + PhoneNo + "\"";
                str1 = this.ExecCommand(port, command1, 300, "Failed to accept phoneNo");

                string command2 = Message + char.ConvertFromUtf32(26) + "\r";
                string str2 = this.ExecCommand(port, command2, 3000, "Failed to send message");

                if (str2.EndsWith("\r\nOK\r\n"))
                    flag = true;
                else if (str2.Contains("ERROR"))
                    flag = false;
                return flag;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }//end sendMsg

        private static void DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                if (e.EventType != SerialData.Chars)
                    return;
                KtdSms.readNow.Set();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }// end DataReceived

        public bool DeleteMsg(SerialPort port, string p_strCommand)
        {
            bool flag = false;
            try
            {
                string str1 = this.ExecCommand(port, "AT", 300, "No phone connected");
                str1 = this.ExecCommand(port, "AT+CMGF=1", 300, "Failed to set message format.");
                string command = p_strCommand;
                string str2 = this.ExecCommand(port, command, 300, "Failed to delete message");
                if (str2.EndsWith("\r\nOK\r\n"))
                    flag = true;
                if (str2.Contains("ERROR"))
                    flag = false;
                return flag;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }// end DeleteMsg
    }
}
